/*
* RT-Thread Secure
*
* Copyright (c) 2021, Shanghai Real-Thread Electronic Technology Co., Ltd.
*
* All rights reserved.0
*/
#include <drv_clk.h>

#define PNAME(x)                 rt_used static const char x[]
#define RK3568_CLKSEL_CON(x)     (0xFDD20000 + (x)*0x4 + 0x100)
#define RK3568_CLKGATE_CON(x)    (0xFDD20000 + (x)*0x4 + 0x300)
#define RK3568_GLB_SRST_FST      (0xFDD200D4)
#define RK3568_SOFTRST_CON(x)    (0xFDD20000 + (x)*0x4 + 0x400)
#define RK3568_MODE_CON          (0xFDD200C0)
#define RK3568_SDMMC0_CON0       (0xFDD20580)
#define RK3568_SDMMC0_CON1       (0xFDD20584)
#define RK3568_SDMMC1_CON0       (0xFDD20588)
#define RK3568_SDMMC1_CON1       (0xFDD2058C)
#define RK3568_SDMMC2_CON0       (0xFDD20590)
#define RK3568_SDMMC2_CON1       (0xFDD20594)
#define RK3568_EMMC_CON0         (0xFDD20598)
#define RK3568_EMMC_CON1         (0xFDD2059C)

#define RK3568_PMU_MODE_CON0		(0xFDD00080)
#define RK3568_PMU_CLKSEL_CON(x)	(0xFDD00000 + (x) * 0x4 + 0x100)
#define RK3568_PMU_CLKGATE_CON(x)	(0xFDD00000 + (x) * 0x4 + 0x180)
#define RK3568_PMU_SOFTRST_CON(x)	(0xFDD00000 + (x) * 0x4 + 0x200)

PNAME(mux_pll_p) = "xin24m";
PNAME(mux_usb480m_p) = "xin24m;usb480m_phy;clk_rtc_32k";
PNAME(mux_armclk_p) = "apll;gpll";
PNAME(gpll100_gpll75_cpll50_xin24m_p) = "gpll_100m;gpll_75m;cpll_50m;xin24m";
PNAME(gpll100_xin24m_cpll100_p) = "gpll_100m;xin24m;cpll_100m";
PNAME(gpll200_xin24m_cpll100_p) = "gpll_200m;xin24m;cpll_100m";
PNAME(clk_i2c_p) = "gpll_200m;gpll_100m;xin24m;cpll_100m";
PNAME(xin24m_32k_p) = "xin24m;clk_rtc_32k";
PNAME(clk_pdpmu_p) = "ppll;gpll";
PNAME(clk_pwm0_p) = "xin24m;clk_pdpmu";
PNAME(gpll300_gpll200_gpll100_xin24m_p) = "gpll_300m;gpll_200m;gpll_100m;xin24m";
PNAME(gpll150_gpll100_gpll75_xin24m_p) = "gpll_150m;gpll_100m;gpll_75m;xin24m";
PNAME(clk_sdmmc_p) = "xin24m;gpll_400m;gpll_300m;cpll_100m;cpll_50m;clk_osc0_div_750k";

int rockchip_hw_clk_init(void)
{
    rt_clk_fixed_rate_register("xin24m", 24000000); // xin24m = xin_osc0

    /* rk3568 pll */
    rt_clk_rk3568_pll_register("apll", mux_pll_p, 0);
    rt_clk_rk3568_pll_register("dpll", mux_pll_p, 1);
    rt_clk_rk3568_pll_register("gpll", mux_pll_p, 2);
    rt_clk_rk3568_pll_register("cpll", mux_pll_p, 3);
    rt_clk_rk3568_pll_register("npll", mux_pll_p, 4);
    rt_clk_rk3568_pll_register("vpll", mux_pll_p, 5);
    /* ppll & hpll belong to PMU_PLL */
    rt_clk_rk3568_pll_register("ppll", mux_pll_p, 6);
    rt_clk_rk3568_pll_register("hpll", mux_pll_p, 7);

    rt_clk_set_rate(rt_clk_find("apll"), 1416 * 1000 * 1000);
    rt_clk_set_rate(rt_clk_find("dpll"), 780 * 1000 * 1000);
    rt_clk_set_rate(rt_clk_find("gpll"), 1188 * 1000 * 1000);
    rt_clk_set_rate(rt_clk_find("cpll"), 1000 * 1000 * 1000);
    rt_clk_set_rate(rt_clk_find("npll"), 1200 * 1000 * 1000);
    rt_clk_set_rate(rt_clk_find("vpll"), 24 * 1000 * 1000);

    rt_clk_set_rate(rt_clk_find("ppll"), 200 * 1000 * 1000);
    rt_clk_set_rate(rt_clk_find("hpll"), 24 * 1000 * 1000);

    /* clk_branches */
    rt_clk_rk3568_composite_register("gpll_400m", "gpll",
        0, 0, 0,
        RK3568_CLKGATE_CON(35), 0, RT_TRUE,
        RK3568_CLKSEL_CON(75), 0, 5, RT_TRUE);

    rt_clk_rk3568_composite_register("gpll_300m", "gpll",
        0, 0, 0,
        RK3568_CLKGATE_CON(35), 1, RT_TRUE,
        RK3568_CLKSEL_CON(75), 8, 5, RT_TRUE);

    rt_clk_rk3568_composite_register("gpll_200m", "gpll",
        0, 0, 0,
        RK3568_CLKGATE_CON(35), 2, RT_TRUE,
        RK3568_CLKSEL_CON(76), 0, 5, RT_TRUE);

    rt_clk_rk3568_composite_register("gpll_150m", "gpll",
        0, 0, 0,
        RK3568_CLKGATE_CON(35), 3, RT_TRUE,
        RK3568_CLKSEL_CON(76), 8, 5, RT_TRUE);

    rt_clk_rk3568_composite_register("gpll_100m", "gpll",
        0, 0, 0,
        RK3568_CLKGATE_CON(35), 4, RT_TRUE,
        RK3568_CLKSEL_CON(77), 0, 5, RT_TRUE);

    rt_clk_rk3568_composite_register("gpll_75m", "gpll",
        0, 0, 0,
        RK3568_CLKGATE_CON(35), 5, RT_TRUE,
        RK3568_CLKSEL_CON(77), 8, 5, RT_TRUE);

    rt_clk_rk3568_composite_register("gpll_20m", "gpll",
        0, 0, 0,
        RK3568_CLKGATE_CON(35), 11, RT_TRUE,
        RK3568_CLKSEL_CON(82), 0, 5, RT_TRUE);

    rt_clk_rk3568_composite_register("cpll_100m", "cpll",
        0, 0, 0,
        RK3568_CLKGATE_CON(35), 13, RT_TRUE,
        RK3568_CLKSEL_CON(81), 0, 5, RT_TRUE);

    rt_clk_rk3568_composite_register("cpll_50m", "cpll",
        0, 0, 0,
        RK3568_CLKGATE_CON(35), 13, RT_TRUE,
        RK3568_CLKSEL_CON(81), 0, 5, RT_TRUE);

    /* pclk */
    rt_clk_rk3568_composite_register("pclk_bus", gpll100_gpll75_cpll50_xin24m_p,
        RK3568_CLKSEL_CON(50), 4, 2,
        RK3568_CLKGATE_CON(26), 1, RT_TRUE,
        0, 0, 0, RT_TRUE);

    /* pmu */
    rt_clk_mux_register("clk_pdpmu", clk_pdpmu_p, RK3568_PMU_CLKSEL_CON(2), 15, 1);
    rt_clk_rk3568_composite_register("pclk_pdpmu", "clk_pdpmu",
        0, 0, 0,
        RK3568_PMU_CLKGATE_CON(0), 2, RT_TRUE,
        RK3568_PMU_CLKSEL_CON(2), 0, 5, RT_TRUE);
    rt_clk_gate_register("pclk_pmu", "pclk_pdpmu",
        RK3568_PMU_CLKGATE_CON(0), 6, RT_TRUE);
    rt_clk_gate_register("clk_pmu", "xin24m",
        RK3568_PMU_CLKGATE_CON(0), 7, RT_TRUE);

    /* gpio */
    rt_clk_rk3568_composite_register("dbclk_gpio", xin24m_32k_p,
        RK3568_CLKSEL_CON(72), 14, 1,
        RK3568_CLKGATE_CON(32), 11, RT_TRUE,
        0, 0, 0, RT_TRUE);
    /* gpio0 */
    rt_clk_rk3568_gate_register("pclk_gpio0", "pclk_pdpmu", RK3568_PMU_CLKGATE_CON(1), 9, RT_TRUE);
    rt_clk_rk3568_composite_register("dbclk_gpio0", xin24m_32k_p,
        RK3568_PMU_CLKSEL_CON(6), 15, 1,
        RK3568_PMU_CLKGATE_CON(1), 10, RT_TRUE,
        0, 0, 0, RT_TRUE);
    /* gpio1 */
    rt_clk_rk3568_gate_register("pclk_gpio1", "pclk_bus", RK3568_CLKGATE_CON(31), 2, RT_TRUE);
    rt_clk_rk3568_gate_register("dbclk_gpio1", "dbclk_gpio", RK3568_CLKGATE_CON(31), 3, RT_TRUE);
    /* gpio2 */
    rt_clk_rk3568_gate_register("pclk_gpio2", "pclk_bus", RK3568_CLKGATE_CON(31), 4, RT_TRUE);
    rt_clk_rk3568_gate_register("dbclk_gpio2", "dbclk_gpio", RK3568_CLKGATE_CON(31), 5, RT_TRUE);
    /* gpio3 */
    rt_clk_rk3568_gate_register("pclk_gpio3", "pclk_bus", RK3568_CLKGATE_CON(31), 6, RT_TRUE);
    rt_clk_rk3568_gate_register("dbclk_gpio3", "dbclk_gpio", RK3568_CLKGATE_CON(31), 7, RT_TRUE);
    /* gpio4 */
    rt_clk_rk3568_gate_register("pclk_gpio4", "pclk_bus", RK3568_CLKGATE_CON(31), 8, RT_TRUE);
    rt_clk_rk3568_gate_register("dbclk_gpio4", "dbclk_gpio", RK3568_CLKGATE_CON(31), 9, RT_TRUE);

    /* i2c */
    rt_clk_rk3568_composite_register("clk_i2c", clk_i2c_p,
        RK3568_CLKSEL_CON(71), 8, 2,
        RK3568_CLKGATE_CON(32), 10, RT_TRUE,
        0, 0, 0, RT_TRUE);
    /* i2c0 */
    rt_clk_rk3568_gate_register("pclk_i2c0", "pclk_pdpmu", RK3568_PMU_CLKGATE_CON(1), 0, RT_TRUE);
    rt_clk_rk3568_composite_register("clk_i2c0", "clk_pdpmu",
        0, 0, 0,
        RK3568_PMU_CLKGATE_CON(1), 1, RT_TRUE,
        RK3568_PMU_CLKSEL_CON(3), 0, 7, RT_TRUE);
    /* i2c1 */
    rt_clk_rk3568_gate_register("pclk_i2c1", "pclk_bus", RK3568_CLKGATE_CON(30), 0, RT_TRUE);
    rt_clk_rk3568_gate_register("clk_i2c1", "clk_i2c", RK3568_CLKGATE_CON(30), 1, RT_TRUE);
    /* i2c2 */
    rt_clk_rk3568_gate_register("pclk_i2c2", "pclk_bus", RK3568_CLKGATE_CON(30), 2, RT_TRUE);
    rt_clk_rk3568_gate_register("clk_i2c2", "clk_i2c", RK3568_CLKGATE_CON(30), 3, RT_TRUE);
    /* i2c3 */
    rt_clk_rk3568_gate_register("pclk_i2c3", "pclk_bus", RK3568_CLKGATE_CON(30), 4, RT_TRUE);
    rt_clk_rk3568_gate_register("clk_i2c3", "clk_i2c", RK3568_CLKGATE_CON(30), 5, RT_TRUE);
    /* i2c4 */
    rt_clk_rk3568_gate_register("pclk_i2c4", "pclk_bus", RK3568_CLKGATE_CON(30), 6, RT_TRUE);
    rt_clk_rk3568_gate_register("clk_i2c4", "clk_i2c", RK3568_CLKGATE_CON(30), 7, RT_TRUE);
    /* i2c5 */
    rt_clk_rk3568_gate_register("pclk_i2c5", "pclk_bus", RK3568_CLKGATE_CON(30), 8, RT_TRUE);
    rt_clk_rk3568_gate_register("clk_i2c5", "clk_i2c", RK3568_CLKGATE_CON(30), 9, RT_TRUE);

    /* spi */
    /* spi0 */
    rt_clk_rk3568_gate_register("pclk_spi0", "pclk_bus", RK3568_CLKGATE_CON(30), 10, RT_TRUE);
    rt_clk_rk3568_composite_register("clk_spi0", gpll200_xin24m_cpll100_p,
        RK3568_CLKSEL_CON(72), 0, 1,
        RK3568_CLKGATE_CON(30), 11, RT_TRUE,
        0, 0, 0, RT_TRUE);
    /* spi1 */
    rt_clk_rk3568_gate_register("pclk_spi1", "pclk_bus", RK3568_CLKGATE_CON(30), 12, RT_TRUE);
    rt_clk_rk3568_composite_register("clk_spi1", gpll200_xin24m_cpll100_p,
        RK3568_CLKSEL_CON(72), 2, 1,
        RK3568_CLKGATE_CON(30), 13, RT_TRUE,
        0, 0, 0, RT_TRUE);
    /* spi2 */
    rt_clk_rk3568_gate_register("pclk_spi2", "pclk_bus", RK3568_CLKGATE_CON(30), 14, RT_TRUE);
    rt_clk_rk3568_composite_register("clk_spi2", gpll200_xin24m_cpll100_p,
        RK3568_CLKSEL_CON(72), 4, 1,
        RK3568_CLKGATE_CON(30), 15, RT_TRUE,
        0, 0, 0, RT_TRUE);
    /* spi3 */
    rt_clk_rk3568_gate_register("pclk_spi3", "pclk_bus", RK3568_CLKGATE_CON(31), 0, RT_TRUE);
    rt_clk_rk3568_composite_register("clk_spi3", gpll200_xin24m_cpll100_p,
        RK3568_CLKSEL_CON(72), 6, 1,
        RK3568_CLKGATE_CON(31), 1, RT_TRUE,
        0, 0, 0, RT_TRUE);

    /* pwm */
    /* pwm0 */
    rt_clk_rk3568_gate_register("pclk_pwm0", "pclk_pdpmu", RK3568_PMU_CLKGATE_CON(1), 6, RT_TRUE);
    rt_clk_rk3568_composite_register("clk_pwm0", clk_pwm0_p,
        RK3568_PMU_CLKSEL_CON(6), 7, 1,
        RK3568_PMU_CLKGATE_CON(1), 7, RT_TRUE,
        RK3568_PMU_CLKSEL_CON(6), 0, 7, RT_TRUE);
    rt_clk_rk3568_gate_register("clk_capture_pwm0_ndft", "xin24m", RK3568_PMU_CLKGATE_CON(1), 8, RT_TRUE);
    /* pwm1 */
    rt_clk_rk3568_gate_register("pclk_pwm1", "pclk_bus", RK3568_CLKGATE_CON(31), 10, RT_TRUE);
    rt_clk_rk3568_composite_register("clk_pwm1", gpll100_xin24m_cpll100_p,
        RK3568_CLKSEL_CON(72), 8, 2,
        RK3568_CLKGATE_CON(31), 11, RT_TRUE,
        0, 0, 0, RT_TRUE);
    rt_clk_rk3568_gate_register("clk_pwm1_capture", "xin24m", RK3568_CLKGATE_CON(31), 12, RT_TRUE);
    /* pwm2 */
    rt_clk_rk3568_gate_register("pclk_pwm2", "pclk_bus", RK3568_CLKGATE_CON(31), 13, RT_TRUE);
    rt_clk_rk3568_composite_register("clk_pwm2", gpll100_xin24m_cpll100_p,
        RK3568_CLKSEL_CON(72), 10, 2,
        RK3568_CLKGATE_CON(31), 14, RT_TRUE,
        0, 0, 0, RT_TRUE);
    rt_clk_rk3568_gate_register("clk_pwm2_capture", "xin24m", RK3568_CLKGATE_CON(31), 15, RT_TRUE);
    /* pwm3 */
    rt_clk_rk3568_gate_register("pclk_pwm3", "pclk_bus", RK3568_CLKGATE_CON(32), 0, RT_TRUE);
    rt_clk_rk3568_composite_register("clk_pwm3", gpll100_xin24m_cpll100_p,
        RK3568_CLKSEL_CON(72), 12, 2,
        RK3568_CLKGATE_CON(32), 1, RT_TRUE,
        0, 0, 0, RT_TRUE);
    rt_clk_rk3568_gate_register("clk_pwm3_capture", "xin24m", RK3568_CLKGATE_CON(32), 2, RT_TRUE);

    rt_clk_rk3568_composite_register("aclk_php", gpll300_gpll200_gpll100_xin24m_p,
        RK3568_CLKSEL_CON(30), 0, 2,
        RK3568_CLKGATE_CON(14), 8, RT_TRUE,
        0, 0, 0, RT_TRUE);
    rt_clk_rk3568_composite_register("hclk_php", gpll150_gpll100_gpll75_xin24m_p,
        RK3568_CLKSEL_CON(30), 0, 2,
        RK3568_CLKGATE_CON(14), 8, RT_TRUE,
        0, 0, 0, RT_TRUE);

    /* sdmmc0 */
    rt_clk_rk3568_composite_register("clk_osc0_div_750k", "xin24m",
        0, 0, 0,
        RK3568_CLKGATE_CON(35), 15, RT_TRUE,
        RK3568_CLKSEL_CON(82), 8, 6, RT_TRUE);

    rt_clk_rk3568_gate_register("hclk_sdmmc0", "hclk_php", RK3568_CLKGATE_CON(15), 0, RT_TRUE);
    rt_clk_rk3568_composite_register("clk_sdmmc0", clk_sdmmc_p,
        RK3568_CLKSEL_CON(30), 8, 3,
        RK3568_CLKGATE_CON(15), 1, RT_TRUE,
        0, 0, 0, RT_TRUE);
    rt_clk_set_parent(rt_clk_find("clk_sdmmc0"), rt_clk_find("cpll_100m"));

    return RT_EOK;
}
INIT_BOARD_EXPORT(rockchip_hw_clk_init);
// MSH_CMD_EXPORT_ALIAS(rockchip_hw_clk_init, rockchip_hw_clk_init, rockchip_hw_clk_init.);
